//! Passing information(`Sized + Copy + Default + 'static`) between threads

use crate::base::{CVoid, RTTError};
use core::marker::PhantomData;
use core::mem;
use core::default::Default;
use crate::base::rttbase_queue_create;
use crate::base::rttbase_queue_send_wait;
use crate::base::rttbase_queue_receive;
use crate::base::rttbase_queue_delete;

unsafe impl<T: Sized + Copy + Default + 'static> Send for Queue<T> {}
unsafe impl<T: Sized + Copy + Default + 'static> Sync for Queue<T> {}

#[derive(Debug)]
pub struct Queue<T: Sized + Copy + Default + 'static> {
    queue: *const CVoid,
    /* only for store item type */
    item_type: PhantomData<T>,
}

impl<T: Sized + Copy + Default + 'static> Queue<T> {
    pub fn new(max_size: usize) -> Result<Queue<T>, RTTError> {
        let item_size = mem::size_of::<T>();
        let handle =
            rttbase_queue_create(max_size, item_size);

        if handle == 0 as *const _ {
            return Err(RTTError::OutOfMemory);
        }
        Ok(Queue {
            queue: handle,
            item_type: PhantomData,
        })
    }

    pub fn send(&self, item: T) -> Result<(), RTTError> {
        Self::send_wait(&self, item, 0)
    }

    pub fn send_wait(&self, item: T, max_wait: i32) -> Result<(), RTTError> {
            if rttbase_queue_send_wait(self.queue,
                                      &item as *const _ as *const CVoid,
                                       mem::size_of::<T>(),
                                        max_wait) != 0 {
                Err(RTTError::QueueSendTimeout)
            } else {
                Ok(())
            }
    }

    pub fn receive(&self, max_wait: i32) -> Result<T, RTTError> {
            let mut buff = Default::default();
            let r = rttbase_queue_receive(self.queue,
                                              &mut buff as *mut _ as *mut CVoid,
                                                mem::size_of::<T>(),
                                              max_wait);
            if r == 0 {
                return Ok(buff);
            } else {
                return Err(RTTError::QueueReceiveTimeout);
            }
    }
}

impl<T: Sized + Copy + Default + 'static> Drop for Queue<T> {
    fn drop(&mut self) {
            rttbase_queue_delete(self.queue);
    }
}
